#!/usr/bin/env python
# -*- python-mode -*-
"""Emulate iostat for NFS mount points using /proc/self/mountstats
"""

__copyright__ = """
Copyright (C) 2005, Chuck Lever <cel@netapp.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""

import sys, os, time

Iostats_version = '0.2'

NfsEventCounters = [
    'inoderevalidates',
    'dentryrevalidates',
    'datainvalidates',
    'attrinvalidates',
    'vfsopen',
    'vfslookup',
    'vfspermission',
    'vfsupdatepage',
    'vfsreadpage',
    'vfsreadpages',
    'vfswritepage',
    'vfswritepages',
    'vfsreaddir',
    'vfssetattr',
    'vfsflush',
    'vfsfsync',
    'vfslock',
    'vfsrelease',
    'setattrtrunc',
    'extendwrite',
]

NfsTimeCounters = [
    'filewrite',
    'preparewrite',
    'commitwrite',
    'fileread',
    'fileflush',
    'readpage',
    'readpages',
    'writepage',
    'writepages'
]

NfsByteCounters = [
    'normalreadbytes',
    'readpagebytes',
]

RpcProcedure = [
    'GETATTR',
    'SETATTR',
    'LOOKUP',
    'ACCESS',
    'CREATE',
    'RENAME',
    'MKDIR',
    'RMDIR',
    'READDIR',
    'STATFS',
    'FSINFO',
    'GETBLKS',
]

class DeviceData:
    """DeviceData objects provide methods for parsing and displaying
    data for a single mount grabbed from /proc/self/mountstats
    """
    def __init__(self):
        self.__nfs_data = dict()
        self.__rpc_count = dict()
	self.__rpc_time = dict()

    def __parse_nfs_line(self, words):
	if len(words) == 0:
	    return
	if words[0] == 'time:':
            i = 1
            for key in NfsTimeCounters:
		self.__nfs_data[key] = long(words[i])
                i += 1
	elif words[0] == 'bytes:':
	    i = 1
            for key in NfsByteCounters:
		self.__nfs_data[key] = long(words[i])
                i += 1

	elif words[0] == 'events:':
	    i = 1
	    for key in NfsEventCounters:
	        self.__nfs_data[key] = long(words[i])
	        i += 1
  	elif words[0] == 'rpc_count:':
	    i = 1
	    for key in RpcProcedure:
	  	self.__rpc_count[key] = long(words[i])
		i += 1
        elif words[0] == 'rpc_time:':
	    i = 1
	    for key in RpcProcedure:
	        self.__rpc_time[key] = long(words[i])
		i += 1
		   
    def parse_stats(self, filename):
        f = file(filename)	
	for line in f.readlines():
            words = line.split()
            self.__parse_nfs_line(words)
    
    def display_iostats(self):
        """Display NFS and RPC stats
        """
	print '***enfs time(ms):***'
	for key in NfsTimeCounters:
	    print '%15s\t %d' %(key, self.__nfs_data[key])
	
	print '***enfs bytes:***'
	for key in NfsByteCounters:
	    print '%15s\t %d' %(key, self.__nfs_data[key])

	
	print '***enfs events:***'
	for key in NfsEventCounters:
	    print '%18s\t %d' % (key, self.__nfs_data[key])

	print '*** rpc statistics***'
	print 'rpcname     rpc_count    rpc_time(ms)'
	for key in RpcProcedure:
	    print '%8s %10d  %10d' %(key, self.__rpc_count[key], self.__rpc_time[key]) 	
	
#
# Functions
#

def print_iostat_summary(filename):
    stats = DeviceData()
    stats.parse_stats(filename)
    stats.display_iostats()

def iostat_command(self):
    filename = sys.argv[1]
    print_iostat_summary(filename)
#
# Main
#
prog = os.path.basename(sys.argv[0])

try:
    iostat_command(prog)
except KeyboardInterrupt:
    print 'Caught ^C... exiting'
    sys.exit(1)

sys.exit(0)
